
#include "KDNode.h"

KDNode::KDNode(float xDim, float yDim, float zDim, int s, Location l, KDNode *par) : 
size(s), loc(l), numObjects(0), hasTrees(false)	{
	dims[0] = xDim;
	dims[1] = yDim;
	dims[2] = zDim;
	left = 0;
	right = 0;
	splitAxis = computeAxis();
	if (size > 1) childNodes();
	parent = par;
	//*left = NULL;
	//*right = NULL;
}

KDNode::~KDNode(void) {
	std::cout << "Deleting KD Node.\n";

	// ASK BOSSMAN HOW TO HANDLE THIS
	/*std::list<WorldObject *>::iterator iter =  nodeList.begin();
	while( iter != nodeList.end() ) {
		std::cout << "Deleting object " << &iter << "\n";
		delete &iter;
		iter++;
    }*/

	nodeList.clear();
}

void KDNode::addObject(WorldObject *toAdd) {
	if (getSize() == toAdd->getSize()) {
		nodeList.push_back(toAdd);
	} else {
		if (left == 0 || right == 0) {
			childNodes();
		}
		if (toAdd->getLocation().getVal(splitAxis) <= loc.getVal(splitAxis)) {
			left->addObject(toAdd);
		} else {
			right->addObject(toAdd);
		}
	}
}

void KDNode::removeObject(WorldObject *toRemove) {
	nodeList.remove(toRemove);
}

void KDNode::clear() {
	nodeList.clear();
}

void KDNode::childNodes(void) {
	float newDims[3] = {dims[0],dims[1],dims[2]};
	newDims[splitAxis] /= 2;

	float newLoc[3] = {loc.getVal(0),loc.getVal(1),loc.getVal(2)};

	newLoc[splitAxis] = newLoc[splitAxis] + newDims[splitAxis] / 2;

	Location rightLoc(newLoc[0],newLoc[1],newLoc[2]);

	newLoc[splitAxis] = newLoc[splitAxis] - newDims[splitAxis];

	Location leftLoc(newLoc[0],newLoc[1],newLoc[2]);

	left = (new KDNode(newDims[0],newDims[1],newDims[2],
		(((size / 10) > 0)?(size/10):1),leftLoc,this));
	right = (new KDNode(newDims[0],newDims[1],newDims[2],
		(((size / 10) > 0)?(size/10):1),rightLoc,this));
}

float KDNode::getXDim() {
	return dims[0];
}

float KDNode::getYDim() {
	return dims[1];
}

float KDNode::getZDim() {
	return dims[2];
}

bool KDNode::containsTrees(void) {
	return hasTrees;
}



void KDNode::setTrees(bool trees) {
	hasTrees = trees;
}

int KDNode::computeAxis(void) {
	float x = dims[0];
	float y = dims[1];
	float z = dims[2];
	if (x >= y && x >= z) return 0;
	if (y >= x && y >= z) return 1;
	return 2;
}

bool KDNode::contains(WorldObject *cont) {
	std::list<WorldObject *>::iterator iter =  nodeList.begin();

	while( iter != nodeList.end() ) {
		if (cont == *iter) return true;
		++iter;
    }

	return false;
}

void KDNode::setRightNode(int nodePtr) {
	right = (KDNode*)nodePtr;
}

void KDNode::setLeftNode(int nodePtr) {
	left = (KDNode*)nodePtr;
}

std::list<WorldObject *> KDNode::getContents(void) {
	std::list<WorldObject *> ret;
	ret = std::list<WorldObject *>(nodeList);
	return ret;
}

std::list<WorldObject *> KDNode::getDrawList(void) {

	std::list<WorldObject *> ret;

	std::list<WorldObject *>::iterator iter =  nodeList.begin();

	while( iter != nodeList.end() ) {
		if ((*iter)->draw())
			ret.push_back(*iter);
		++iter;
	}

	if(left != 0)
		ret.splice(ret.end(),left->getDrawList());
	if(right != 0)
		ret.splice(ret.end(),right->getDrawList());

	// std::cout << "Getting draw list of size" << ret.size() << "\n";

	return ret;
}

void KDNode::printNode(void) {
	std::cout << "\nPRINTING NODE\n";
	std::cout << "=======================================\n";
	std::cout << "Location: " << loc.getVal(0) << " " << loc.getVal(1) << " " << loc.getVal(2) << "\n";
	std::cout << "Size: " << dims[0] << " " << dims[1] << " " << dims[2] << "\n";
	std::cout << "Node Size: " << size << "\n";
	std::cout << "=======================================\n";
	std::cout << "OBJECTS\n";

	std::list<WorldObject *>::iterator iter =  nodeList.begin();
	while( iter != nodeList.end() ) {
		std::cout << "Object : " << (*iter)->getLocation().getVal(0) 
			<< " " << (*iter)->getLocation().getVal(1) 
			<< " " << (*iter)->getLocation().getVal(2) << "\n";
		 ++iter;
    }

	std::cout << "=======================================\n\n";
}

void KDNode::update(void) {
	
//	std::list<WorldObject *> removeList;

	std::list<WorldObject *>::iterator iter =  nodeList.begin();
	while( iter != nodeList.end() ) {
		(*iter)->update();
		/*if ((*iter)->deleteMe())
			removeList.push_back((*iter));*/
		 ++iter;
    }

	if (left != 0)
		left->update();
	if (right != 0)
		right->update();

/*	std::cout << "Removing some shit...\n" << removeList.size();
	iter = removeList.begin();
	while( iter != removeList.end() ) {
		nodeList.remove((*iter));
    }
*/

}

Location KDNode::getLocation(void) {
	return loc;
}

int KDNode::getSize(void) {
	return size;
}

KDNode * KDNode::getParent() {
	return parent;
}

KDNode *KDNode::leftNode(void) {
	return left;
}

KDNode *KDNode::rightNode(void) {
	return right;
}